import 'dart:convert';
import 'package:web_socket_channel/io.dart';
import 'package:flutter_tools/string_extension.dart';
import 'models/error_model.dart';
import 'refresh_token_proxy.dart';

typedef OnDoneCallback = void Function();
typedef OnDataCallback = void Function<T>(T event);
typedef OnConnectCallback = void Function();

class WxWebSocket{
  final String url;
  int repeatCount;

  Function onError;
  OnDoneCallback onDone;
  OnDataCallback onData;
  OnConnectCallback onConnectCallback;

  bool cancelOnError;

  IOWebSocketChannel _channel;
  
  WxWebSocket(this.url, {this.repeatCount = 3, this.onConnectCallback,this.onData,this.onDone,this.onError,this.cancelOnError});

  factory WxWebSocket.connect(url,
  {int repeatCount,
    OnConnectCallback onConnectCallback,
  OnDataCallback onData,
  OnDoneCallback onDone,
  Function onError,
  bool cancelOnError}) {
    WxWebSocket webSocket = WxWebSocket(url,
    repeatCount: repeatCount,
    onData: onData,
    onDone: onDone,
    onError: onError,
    cancelOnError: cancelOnError,
    onConnectCallback: onConnectCallback);
    Future.delayed(Duration(milliseconds:500),(){
      webSocket._connect();
    });
    return webSocket;
  }

  void _connect() {
    if(_channel != null){
      _channel.sink.close();
      _channel = null;
    }
    _channel = IOWebSocketChannel.connect(url);
    _channel.stream.listen(_data, onError: _error, onDone: _done);
    if(onConnectCallback != null){
      onConnectCallback();
    }
  }

  void sendMessage(String data) {
    _channel.sink.add(data);
  }

  void _error(error){
    if (repeatCount < 3) {
      repeatCount ++;
      close();
      _connect();
    } else {
      if (onError != null) {
        onError();
      }
    }
  }

  void _done() {
    if (onDone != null) {
      onDone();
    }
  }
//  {"errorId":"401","errorMsg":"auth failed!","snapShort":false}
  void _data(data) {
    dynamic result = json.decode(data);
    if (result is Map) {
      Map dic = result;
      String errorId = dic['errorId'];
      if (CusNetworkError.unauthorized == errorId.toInt) {
        RefreshTokenProxy.getInstance().refreshAndHandle((){
          _connect();
        });
      }
    }
    if (onData != null) {
      onData(data);
    }
  }

  void close() {
    _channel.sink.close();
  }
}

